package com.intramirror.product.service.impl;

import com.intramirror.product.algorithm.AggregateFactory;
import static com.intramirror.product.constant.AggregateConstant.SCHEDULE_AGGREGATE_USERID;
import static com.intramirror.product.constant.AggregateConstant.TPYE_PRE_AGGREGATE_WITH_RULE;
import static com.intramirror.product.constant.AggregateConstant.TYPE_SCHEDULE_AGGREGATE;

import com.intramirror.product.entity.AggregateRule;
import com.intramirror.product.entity.AggregateRuleType;
import com.intramirror.product.entity.Product;
import com.intramirror.product.entity.Spu;
import com.intramirror.product.entity.SpuAggregateLog;
import com.intramirror.product.entity.SpuBoutiqueImgSort;
import com.intramirror.product.entity.SpuInexactProduct;
import com.intramirror.product.exception.BusinessException;
import com.intramirror.product.mapper.AggregateMapper;
import com.intramirror.product.mapper.ProductMapper;
import com.intramirror.product.mapper.SpuBoutiqueImgSortMapper;
import com.intramirror.product.mapper.SpuMapper;
import com.intramirror.product.service.IAggregateService;
import com.intramirror.product.service.ISpuLogService;
import com.intramirror.product.service.ISpuService;
import com.intramirror.product.utils.AggregateRuleManagement;
import com.intramirror.product.utils.ConvertUtil;
import com.intramirror.product.utils.SeasonUtil;
import com.intramirror.utils.transform.JsonTransformUtil;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * Created on 2018/1/28.
 * @author 123
 */
@Service
public class AggregateServiceImpl implements IAggregateService {
    private static final Logger LOGGER = LoggerFactory.getLogger(AggregateServiceImpl.class);

    @Autowired
    AggregateMapper aggregateMapper;

    @Autowired
    ProductMapper productMapper;

    @Autowired
    SpuMapper spuMapper;

    @Autowired
    SpuBoutiqueImgSortMapper spuBoutiqueImgSortMapper;

    @Autowired
    ISpuService spuService;

    @Autowired
    ISpuLogService spuLogService;

    @Autowired
    AggregateFactory aggregateFactory;

    @Override
    public List<AggregateRule> listAllAggregateRule() {
        return aggregateMapper.getAllAggregateRule();
    }

    @Override
    public List<Product> getUnAggregatedProduct(Long productId, int pos, int limit) {
        return productMapper.getUnAggregatedProduct(productId, pos, limit);
    }

    @Override
    public Spu aggregateToExistsSpu(Product product) throws BusinessException {
        AggregateRule rule = AggregateRuleManagement.getInstance().getRule(product.getVendorId(), product.getBrandId());
        if (rule == null) {
            LOGGER.debug("Could not find any rule for product id {}.", product.getProductId());
            return null;
        }

        AggregateRuleType ruleType = AggregateRuleType.valueOf(rule.getType());
        Spu spu = aggregateFactory.getAggregateAlgorithm(ruleType).aggregateWithPattern(product, rule.getPattern());
        List<Map<String, Object>> dbSpu = aggregateMapper.findSpuByDesignerIdAndColorCode(spu);
        if (dbSpu == null || dbSpu.size() == 0) {
            return null;
        } else {
            Long spuId = ConvertUtil.toLong(dbSpu.get(0).get("spu_id"));
            return spuMapper.selectByPrimaryKey(spuId);
        }

    }

    @Override
    public Spu aggregateProduct(Product product) throws BusinessException {
        // 聚合商品
        AggregateRule rule = AggregateRuleManagement.getInstance().getRule(product.getVendorId(), product.getBrandId());
        if (rule == null) {
            LOGGER.debug("Could not find any rule for product id {}.", product.getProductId());
            return null;
        }

        AggregateRuleType ruleType = AggregateRuleType.valueOf(rule.getType());
        Spu spu = aggregateFactory.getAggregateAlgorithm(ruleType).aggregateWithPattern(product, rule.getPattern());

        if ("CarryOver".equalsIgnoreCase(product.getSeasonCode())) {
            spu.setSeasonCode(SeasonUtil.carryOverToNewSeasonCode());
        } else {
            spu.setSeasonCode(product.getSeasonCode());
        }

        SpuAggregateLog log = new SpuAggregateLog();
        log.setType(TYPE_SCHEDULE_AGGREGATE);
        log.setUserId(SCHEDULE_AGGREGATE_USERID);
        log.setTargetColorCode(spu.getColorCode());
        log.setTargetDesignerId(spu.getDesignerId());
        log.setProductId(product.getProductId());
        log.setPattern(rule.getPattern());
        log.setSrcColorCode(product.getColorCode());
        log.setSrcDesignerId(product.getDesignerId());
        log.setSeasonCode(product.getSeasonCode());
        log.setSrcSpuId(0L);
        if (spu.getSpuId() != null) {
            log.setType(TPYE_PRE_AGGREGATE_WITH_RULE);
            log.setPattern("{}");
            log.setTargetSpuId(spu.getSpuId());
        }

        Spu returnSpu = null;
        List<Map<String, Object>> dbSpu = aggregateMapper.findSpuByDesignerIdAndColorCode(spu);
        if (dbSpu == null || dbSpu.size() == 0) {
            // 聚合到新到SPU中
            List<String> imgList = spuService.sImgToList(product.getCoverImg());
            if (imgList.size() < 2) {
                LOGGER.debug("Product cover image is less then 2, can not aggregate new spu.");
                return null;
            }

            returnSpu = aggregateProductToNewSpu(product.getProductId(), spu.getDesignerId(), spu.getColorCode());
            log.setTargetSpuId(returnSpu.getSpuId());

        } else {
            // 聚合到已有到SPU中
            Long spuId = ConvertUtil.toLong(dbSpu.get(0).get("spu_id"));
            Boolean descModify = (Boolean) dbSpu.get(0).get("desc_modify");
            String spuName = ConvertUtil.toString(dbSpu.get(0).get("spu_name"));
            String spuDescription = ConvertUtil.toString(dbSpu.get(0).get("spu_description"));
            Boolean spuImgModified = (Boolean) dbSpu.get(0).get("img_modified");
            Long spuVendorId = ConvertUtil.toLong(dbSpu.get(0).get("vendor_id"));
            String spuBoutiqueImg = ConvertUtil.toString(dbSpu.get(0).get("boutique_img"));

            boolean needMerge = isEmpty(spuName);
            boolean updateFlag = false;
            needMerge = (needMerge | isEmpty(spuDescription));

            if ((descModify == null || !descModify) && !needMerge) {
                needMerge = needMergeSpuNameAndDescription(spuId, product);
                LOGGER.debug("Need to update spu name to {} and desc to {}.", spuName, spuDescription);
            }

            Spu updateSpu = new Spu();
            updateSpu.setSpuId(spuId);
            //商品同时存在名称和描述才更新
            if (needMerge && StringUtils.isNotBlank(product.getName()) && StringUtils.isNotBlank(product.getDescription())) {
                updateSpu.setSpuName(product.getName());
                updateSpu.setSpuDescription(product.getDescription());
                updateFlag = true;
            }

            // spuService.dealBoutiqueImg(null, spuId, product.getProductId());
            List<String> imgList = spuService.sImgToList(product.getCoverImg());
            List<String> spuImgList = spuService.sImgToList(spuBoutiqueImg);

            /*
             * 判断SPU图片是否需要更新
             * 1. 判断spu的BoutiqueImg数量为0且商品的CoverImg数量为3张以上则需要更新，否则进行下一步判断
             * 2. 判断商品的CoverImg为3张以上且spu的ImgModified为false则进行下一步判断，否则不用更新
             * 3. 判断商品的ImgModified为true则需要更新，否则进行下一步判断
             * 4. 判断spu的图片质量不佳，数量为3张以下则需要更新，否则进行下一步判断
             * 5. 如果商品的vendorId优先级高于spu的vendorId则需要更新，否则不需要更新
             */
            if (spuImgList.size() > 0) {
                if (imgList.size() >= 3 && (spuImgModified == null || !spuImgModified)) {
                    if (product.getImgModified() != null && product.getImgModified()) {
                        LOGGER.debug("aggregateProduct---------------updateImage:imgModifiedCheck");
                        setModifiedImg(updateSpu, product, imgList);
                        updateFlag = true;
                    } else if (spuImgList.size() < 3) {
                        LOGGER.debug("aggregateProduct---------------updateImage:spu image less then 3");
                        setModifiedImg(updateSpu, product, imgList);
                        updateFlag = true;
                    } else if (vendorSortCheck(spuVendorId, product.getVendorId())) {
                        LOGGER.debug("aggregateProduct---------------updateImage:vendorSortCheck");
                        setModifiedImg(updateSpu, product, imgList);
                        updateFlag = true;
                    }
                }
            } else {
                LOGGER.debug("aggregateProduct---------------updateImage:vendorSortCheck");
                if (imgList.size() < 2) {
                    LOGGER.warn("Product cover image and spu image both less then 2, can not aggregate to spu.");
                    return null;
                } else if (imgList.size() >= 3) {
                    setModifiedImg(updateSpu, product, imgList);
                    updateFlag = true;
                }
            }

            if (updateFlag) {
                aggregateMapper.updateSpu(updateSpu);
            }
            returnSpu = updateSpu;
            productMapper.updateProductSpuInfo(product.getProductId(), spuId);
            log.setTargetSpuId(spuId);
        }

        spuLogService.addSpuAggregateLog(log);
        return returnSpu;
    }

    private boolean vendorSortCheck(Long spuVendorId, Long productVendorId) {
        Map<Long, Integer> boutiqueImgSortMap = AggregateRuleManagement.getInstance().getBoutiqueImgSortMap();
        //找不到排序位置的vendor id则把优先级定成最低，不用它的图片
        Integer spuSort = boutiqueImgSortMap.get(spuVendorId) != null ? boutiqueImgSortMap.get(spuVendorId) : 10001;
        Integer prdSort = boutiqueImgSortMap.get(productVendorId) != null ? boutiqueImgSortMap.get(productVendorId) : 10000;
        return prdSort < spuSort;
    }

    private void setModifiedImg(Spu updateSpu, Product product, List<String> imgList) {
        if (product.getImgModified() != null && product.getImgModified()) {
            updateSpu.setBoutiqueImg(JsonTransformUtil.toJson(imgList.subList(0, 2)));
            updateSpu.setModelImg(JsonTransformUtil.toJson(imgList.subList(2, imgList.size())));
            updateSpu.setImgModified(Boolean.TRUE);
            updateSpu.setVendorId(-1L);
        } else {
            updateSpu.setBoutiqueImg(product.getCoverImg());
            updateSpu.setVendorId(product.getVendorId());
        }
        updateSpu.setCoverImg(spuService.dealCoverImg(updateSpu));
        updateSpu.setDescImg(spuService.dealDescImg(updateSpu));
    }

    @Override
    public List<SpuBoutiqueImgSort> listAllBoutiqueImgSort() {
        return spuBoutiqueImgSortMapper.getAllBoutiqueImgSort();
    }

    @Override
    public Spu aggregateProductToNewSpu(Long productId, String designerId, String colorCode) {

        // 聚合商品
        Spu spu = new Spu();
        spu.setDesignerId(designerId);
        spu.setColorCode(colorCode);
        spu.setDesignerColor(designerId + colorCode);

        Product product = productMapper.selectByPrimaryKey(productId);
        Map<String, Object> brandInfo = productMapper.getBrandInfo(product.getBrandId());
        if ("CarryOver".equalsIgnoreCase(product.getSeasonCode())) {
            spu.setSeasonCode(SeasonUtil.carryOverToNewSeasonCode());
        } else {
            spu.setSeasonCode(product.getSeasonCode());
        }
        String composition = null;

        List<Map<String, Object>> listProductProperty = productMapper.getProductProperty(product.getProductId());
        if (listProductProperty != null && listProductProperty.size() > 0) {
            for (Map<String, Object> property : listProductProperty) {
                if (property.get("key_name") != null && "Composition".equals(property.get("key_name").toString())) {
                    if (property.get("value") != null) {
                        composition = property.get("value").toString();
                    }
                }
            }
        }

        spu.setComposition(composition);
        spu.setBoutiqueImg(product.getCoverImg());
        spu.setBrandId(product.getBrandId());
        spu.setSpuDescription(product.getDescription());
        spu.setSpuName(product.getName());
        spu.setVendorId(product.getVendorId());
        spu.setImgModified(product.getImgModified());

        List<String> imgList = spuService.sImgToList(product.getCoverImg());
        if (product.getImgModified() != null && product.getImgModified() && imgList.size() >= 3) {
            spu.setBoutiqueImg(JsonTransformUtil.toJson(imgList.subList(0, 2)));
            spu.setModelImg(JsonTransformUtil.toJson(imgList.subList(2, imgList.size())));
            spu.setImgModified(Boolean.TRUE);
            spu.setVendorId(-1L);
        }

        spu.setCoverImg(spuService.dealCoverImg(spu));
        spu.setDescImg(spuService.dealDescImg(spu));

        if (brandInfo == null) {
            spu.setBrandName("");
        } else {
            spu.setBrandName((String) brandInfo.get("english_name"));
        }

        aggregateMapper.addSpu(spu);
        LOGGER.debug("Aggregate to a new spu, spu id {}.", spu.getSpuId());
        productMapper.updateProductSpuInfo(product.getProductId(), spu.getSpuId());
        return spu;

    }

    @Override
    public Product selectByPrimaryKey(Long productId) {
        return productMapper.selectByPrimaryKey(productId);
    }

    @Override
    public void insertSpuInexactProduct(SpuInexactProduct spuInexactProduct) {
        aggregateMapper.insertSpuInexactProduct(spuInexactProduct);
    }

    private boolean needMergeSpuNameAndDescription(Long spuId, Product product) {
        if (product.getImgModified() != null && product.getImgModified()) {
            Map<String, Object> condition = new HashMap<>();
            condition.put("spuId", spuId);
            List<Map<String, Object>> listProduct = productMapper.getProductBySpuId(condition);
            for (Map<String, Object> spuProduct : listProduct) {
                Boolean imgModify = (Boolean) spuProduct.get("img_modified");
                if (imgModify != null && imgModify) {
                    // 已经聚合的商品中存在img_modify = 1的product, 不需要更新name和description
                    return false;
                }
            }
            return true;

        }
        return false;
    }

    private boolean isEmpty(String str) {
        return str == null || str.isEmpty();
    }

    @Override
    public List<Product> getUnAggregatedProductInRule(Long productId, int pos, int limit, Long vendorId, List<Long> brandIds) {
        return productMapper.getUnAggregatedProductInRule(productId, pos, limit, vendorId, brandIds);
    }

    @Override
    public void updateBoutiqueSpuImg(Product product, Spu spu) {
        List<String> imgList = spuService.sImgToList(product.getCoverImg());
        if (imgList.size() >= 2) {
            spu.setBoutiqueImg(product.getCoverImg());
            Spu updateSpu = new Spu();
            updateSpu.setSpuId(spu.getSpuId());
            updateSpu.setBoutiqueImg(product.getCoverImg());
            updateSpu.setCoverImg(spuService.dealCoverImg(spu));
            updateSpu.setDescImg(spuService.dealDescImg(spu));
            updateSpu.setVendorId(product.getVendorId());
            aggregateMapper.updateSpu(updateSpu);

            SpuAggregateLog log = new SpuAggregateLog();
            log.setType(TPYE_PRE_AGGREGATE_WITH_RULE);
            log.setUserId(SCHEDULE_AGGREGATE_USERID);
            log.setTargetColorCode(product.getColorCode());
            log.setTargetDesignerId(product.getDesignerId());
            log.setTargetSpuId(spu.getSpuId());
            log.setProductId(product.getProductId());
            log.setPattern("{}");
            log.setSrcColorCode(product.getColorCode());
            log.setSrcDesignerId(product.getDesignerId());
            log.setSeasonCode(product.getSeasonCode());
            log.setSrcSpuId(spu.getSpuId());
            spuLogService.addSpuAggregateLog(log);
            LOGGER.info("SpuUpdateConsumer----------Update Success.");
        } else {
            LOGGER.info("SpuUpdateConsumer----------Update failed.Product cover img size < 2");
        }
    }
}
